#region Namespace References

using System;
using System.Collections.Generic;
using DynConDevCorp.OpenArch.SmartData.Interfaces.Attributes;
using DynConDevCorp.OpenArch.SmartData.Interfaces.EventArgClasses;
using DynConDevCorp.OpenArch.SmartData.Interfaces.MetaData;

#endregion

namespace DynConDevCorp.OpenArch.SmartData.Interfaces
{
    /// <summary>
    /// Base Interface for all Smart Entities.
    /// </summary>
    /// <remarks> 
    /// A Smart entity may contain 1 or more ISmartField instances.
    /// </remarks>
    public interface ISmartEntity : ISmartField, ISmartProperty
    {
        #region Public Instance Properties
 
        /// <summary>
        /// Gets the entity ID.
        /// </summary>
        /// <value>The entity ID.</value>
        Guid EntityID { get; }

        /// <summary>
        /// Gets the field count.
        /// </summary>
        /// <value>The field count.</value>
        int FieldCount { get; }

        /// <summary>
        /// Gets the field names.
        /// </summary>
        /// <value>The field names.</value>
        IList<string> FieldNames { get; }

        /// <summary>
        /// Gets the fields.
        /// </summary>
        /// <value>The fields.</value>
        [Persist(IsXmlPersistable = false, IsDatabaseField = false)]
        ISmartFieldKeyedCollection<string, ISmartField> Fields { get; }

        /// <summary>
        /// Gets a value indicating whether this instance is dynamic entity.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if this instance is dynamic entity; otherwise, <c>false</c>.
        /// </value>
        Boolean IsDynamicEntity { get; }

        /// <summary>
        /// Gets the <see cref="ISmartField"/> with the specified field name.
        /// </summary>
        /// <value></value>
        ISmartField this[string fieldName] { get; }

        /// <summary>
        /// Gets the entity which has direct ownership of this instance.
        /// </summary>
        /// <value>The owning entity.</value>
        ICollection<ISmartEntity> LinkedEntities { get; }

        /// <summary>
        /// Gets the meta entity.
        /// </summary>
        /// <value>The meta entity.</value>
        ISmartMetaEntity MetaEntity { get; }

        /// <summary>
        /// Gets or sets the state of the persistance.
        /// </summary>
        /// <value>The state of the persistance.</value>
        SmartPersistenceState PersistenceState { get; set; }

        #endregion

        #region Public Instance Methods

        /// <summary>
        /// Adds the field effect.
        /// </summary>
        /// <typeparam name="TData">The type of the data.</typeparam>
        /// <param name="fieldName">Name of the field.</param>
        /// <param name="effect">The effect.</param>
        void AddFieldEffect<TData>(string fieldName, ISmartEffect<TData> effect);

        /// <summary>
        /// Adds the field effect.
        /// </summary>
        /// <typeparam name="TData">The type of the data.</typeparam>
        /// <param name="fieldName">Name of the field.</param>
        /// <param name="eventHandler">The event handler.</param>
        void AddFieldEffect<TData>(string fieldName, EventHandler<ValueChangedEventArgs<TData>> eventHandler);

        /// <summary>
        /// Determines whether the specified field name contains field.
        /// </summary>
        /// <param name="fieldName">Name of the field.</param>
        /// <returns>
        /// 	<c>true</c> if the specified field name contains field; otherwise, <c>false</c>.
        /// </returns>
        bool ContainsField(string fieldName);

        /// <summary>
        /// Gets the name of the field.
        /// </summary>
        /// <param name="field">The field.</param>
        /// <returns></returns>
        string GetFieldName(ISmartField field);

        /// <summary>
        /// Propogates the field effects.
        /// </summary>
        /// <typeparam name="TData">The type of the data.</typeparam>
        /// <param name="source">The source.</param>
        /// <param name="args">The <see cref="DynConDevCorp.OpenArch.SmartData.Interfaces.EventArgClasses.ValueChangedEventArgs&lt;TData&gt;"/> instance containing the event data.</param>
        void PropogateFieldEffects<TData>(ISmartField source, ValueChangedEventArgs<TData> args);

        /// <summary>
        /// Registers the auto fields.
        /// </summary>
        void RegisterAutoFields();

        /// <summary>
        /// Registers the field.
        /// </summary>
        /// <param name="fieldName">Name of the field.</param>
        /// <param name="field">The field.</param>
        ISmartField RegisterField(string fieldName, ISmartField field);

        /// <summary>
        /// Registers the field effect at the type level
        /// </summary>
        /// <typeparam name="TData">The type of the data.</typeparam>
        /// <param name="fieldName">Name of the field.</param>
        /// <param name="effect">The effect.</param>
        void RegisterFieldEffectForType<TData>(string fieldName, ISmartEffect<TData> effect);

        /// <summary>
        /// Registers the type of the field effect for.
        /// </summary>
        /// <typeparam name="TData">The type of the data.</typeparam>
        /// <param name="fieldName">Name of the field.</param>
        /// <param name="eventHandler">The event handler.</param>
        void RegisterFieldEffectForType<TData>(string fieldName, EventHandler<ValueChangedEventArgs<TData>> eventHandler);

        /// <summary>
        /// Removes the field effect.
        /// </summary>
        /// <typeparam name="TData">The type of the data.</typeparam>
        /// <param name="fieldName">Name of the field.</param>
        /// <param name="effect">The effect.</param>
        void RemoveFieldEffect<TData>(string fieldName, ISmartEffect<TData> effect);

        /// <summary>
        /// Sets the raw field value.
        /// </summary>
        /// <param name="fieldName">Name of the field.</param>
        /// <param name="value">The value.</param>
        void SetRawFieldValue(string fieldName, object value);

        #endregion

        #region All Other Members

        /// <summary>
        /// Occurs when [field value changed].
        /// </summary>
        event EventHandler<FieldValueChangedEventArgs> FieldValueChanged;

        #endregion
    }
}